﻿using System;
using System.Collections.Generic;
using System.Net.Http;

namespace entrust委托
{
    class Program
    {
        /// <summary>
        /// 定义一个委托 无参无返回值
        /// </summary>
        public delegate void MyDelegate();

        /// <summary>
        /// 定义一个委托 有参无返回值
        /// </summary>
        public delegate void MyDelegate1(int x);

        /// <summary>
        /// 定义一个委托 有参有返回值
        /// </summary>
        public delegate int MyDelegate2(int x);

        /// <summary>
        /// 定义一个委托 有参有返回值
        /// </summary>
        public delegate bool MyDelegateDecide(Student student);

        static void Main(string[] args)
        {
            //委托实例方式
            {
                //传入方法的方式(普通方法，还可以传入静态、实例方法,匿名方法)
                //实例传入 方法不需要带（）
                MyDelegate myDelegate = new MyDelegate(new MyDelegationDeom().Show);
                myDelegate();
                //省略实例 可以直接等于但是效果是一样的
                MyDelegate myDelegate1 = new MyDelegationDeom().Show;
                myDelegate1();
                //多播委托 委托链实现了，将委托用链连接起来，执行的使用从头到尾执行
                MyDelegationDeom myDelegationDeom = new MyDelegationDeom();
                MyDelegate myDelegate2 = new MyDelegationDeom().Show;
                myDelegate2 += myDelegationDeom.Show;
                //多播委托也可以删除,只要将对应的实例方法放入就可以删除之前的添加方法
                myDelegate2 -= myDelegationDeom.Show;
                myDelegate2 -= new MyDelegationDeom().Show;
                myDelegate2.Invoke();
                //往后版本不断的更新实例的方式 
                MyDelegate myDelegate3 = new MyDelegate(new MyDelegationDeom().Show);
                myDelegate3.Invoke();
                //我们可以明显的发现new MyDelegationDeom().Show这个方法使用一次还要去定义方法，会
                //使代码冗余、繁琐。在不断的简化中产生了lambda表达式,lambda表达式就是方法的缩写
                //无参无返回值
                MyDelegate myDelegate4 = new MyDelegate(() => { Console.WriteLine("哈哈"); });
                myDelegate4.Invoke();
                MyDelegate myDelegate5 = () => { Console.WriteLine("哈哈"); };
                myDelegate5.Invoke();
                MyDelegate myDelegate6 = () => Console.WriteLine("哈哈");
                myDelegate6.Invoke();
                //有参无返回值
                MyDelegate1 myDelegate7 = (x) => Console.WriteLine("哈哈");
                myDelegate7.Invoke(5);
                MyDelegate1 myDelegate8 = x => Console.WriteLine("哈哈");
                myDelegate8.Invoke(5);
                //有参有返回值 如果是两个参数的话就一定要加（）了。
                MyDelegate2 myDelegate9 = x => x;
                myDelegate9.Invoke(5);
            }

            //委托调用方式
            {
                MyDelegate myDelegate1 = new MyDelegationDeom().Show;
                //调用Invoke方法 
                myDelegate1.Invoke();
                //直接调用  
                //和上面两个方法一致的效果,也有一步调用方法。
                myDelegate1();
            }

            //委托实战
            {
                //假如我们有一个数据集合我们需要过滤成绩大于200分的学生
                //总数据源
                List<Student> data = new List<Student>();

                //需要拿出来的数据
                List<Student> students = new List<Student>();
                //赛选数据
                data.ForEach(x =>
                {
                    if (x.Score > 200)
                    {
                        students.Add(x);
                    }
                    else if (x.Name.Length > 2)
                    {
                        students.Add(x);
                    }
                });
            }

            //只需要改变委托的传值，其他的不要修改了
            MyDelegateDecide myDelegateDecide = x => x.Score > 200;
            myDelegateDecide += x => x.Name.Length > 2;
            //委托解耦
            {
                //假如我们有一个数据集合我们需要过滤成绩大于200分的学生
                //总数据源
                List<Student> data = new List<Student>();
                GetData(data, myDelegateDecide);
            }


            //Action、Func 委托的使用
            //首先说一下为什么我们在平常开发中基本不会自己定义委托了
            //如果看了GetData的代码，我们明显的发现，我们定义的委托类型就写死了
            //不方便以后的灵活使用.net 就给我们提供了两个标准委托
            //Action是一个有参无返回值的委托  
            //Func是一个有参并且有返回值的委托
            //共同点就是，都有默认最多16个参数，如果以后还想17就需要自己重新这个类
            {
                Action action = () => { Console.WriteLine("无参无返回值"); };
                action.Invoke();
                Action<int> action1 = x => { Console.WriteLine("有参无返回值"); };
                action1.Invoke(5);
                Action<int, int> action2 = (x, y) => { Console.WriteLine("有参无返回值"); };
                action2.Invoke(1,2);
                Func<int, bool> func = x => true;
                func.Invoke(5);
            }

            //事件 重点：委托和事件的区别就在，事件是委托的实例
            //事件不能再声明事件以外的地方调用方法Invoke 、已经不能直接修改事件的方法，只能+= 防止别人修改内部代码
            {
                //这个是直接调用的模式，但是缺点就是下次猫叫发生的动作想要发生变化的时候就需要
                //修这个类的方法，麻烦为了方便日后维护，我们需要将以后需要改动的东西抽了出来
                Miao miao = new Miao();
                miao.Call();

                //这里的话我们要使用事件来进行
                //这里其实就是一个典型的观察者模式，就是使用事件多播，达到动态的执行一些动作
                //很多地方都使用了这样的思想。
                Movement movement = new Movement();
                miao.MyMaoDeomEvent += movement.Swimming;
                miao.MyMaoDeomEvent += movement.Fly;
                miao.MyMaoDeomEvent += movement.Run;
                miao.CallNew();
            }
        }

        /// <summary>
        /// 获取数据源
        /// </summary>
        /// <param name="data"></param>
        /// <param name="myDelegateDecide"></param>
        static List<Student> GetData(List<Student> data, MyDelegateDecide myDelegateDecide)
        {
            //需要拿出来的数据
            List<Student> students = new List<Student>();
            //赛选数据
            data.ForEach(x =>
            {
                if (myDelegateDecide.Invoke(x))
                {
                    students.Add(x);
                }
            });
            return students;
        }
    }
}
